package cn.calm.swing.osgi.api;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import cn.calm.swing.osgi.api.util.ServiceUtil;

public abstract class DefaultServiceTracker<S, T> extends ServiceTracker<S, T> {
	protected final static int ADDED = 1, REMOVED = 2, MODIFIED = 3;

	public DefaultServiceTracker(BundleContext context, Class<S> clazz,
			ServiceTrackerCustomizer<S, T> customizer) {
		super(context, clazz, customizer);
	}

	public DefaultServiceTracker(BundleContext context, Filter filter,
			ServiceTrackerCustomizer<S, T> customizer) {
		super(context, filter, customizer);
	}

	public DefaultServiceTracker(BundleContext context,
			ServiceReference<S> reference,
			ServiceTrackerCustomizer<S, T> customizer) {
		super(context, reference, customizer);
	}

	@Override
	public T addingService(ServiceReference<S> reference) {
		T service = super.addingService(reference);
		processShape(ADDED, reference, service);
		return service;
	}

	protected void processAdd(ServiceReference<S> reference, final T service,final String key,Class<T> clazz){
		String menuTree = String.valueOf(reference.getProperty(MenuService.MENU_TREE));
		int index=menuTree.indexOf("/");
		if(index>0){
			String parentMenuTree=menuTree.substring(0, index);
			try {
				Collection<ServiceReference<T>> serviceReferences = context
						.getServiceReferences(clazz, "(" + key + "="
								+ parentMenuTree + ")");
				if(serviceReferences.isEmpty()){
					return;
				}
				Iterator<ServiceReference<T>> iterator = serviceReferences.iterator();
				// 如果存在获得上级菜单服务的第一个
				if (iterator.hasNext()) {
					ServiceReference<T> next = iterator.next();
					T parent = context.getService(next);
					processParent(service, parent);
					processSubMenuService(next,parent,key,clazz);
				}
			} catch (InvalidSyntaxException e) {
				e.printStackTrace();
			}
		}else{
			try {
				Collection<ServiceReference<T>> serviceReferences = context
						.getServiceReferences(clazz, null);
				List<ServiceReference<T>> list=ServiceUtil.filter(serviceReferences, new cn.calm.swing.osgi.api.Filter<ServiceReference<T>>(){

					@Override
					public boolean filter(ServiceReference<T> e) {
						String menu = String.valueOf(e.getProperty(key));
						return menu.matches("\\w*");
					}
				});
				sortService(list);
				for(ServiceReference<T> ref:list){
					T service1 = context.getService(ref);
					processParent(service1, null);
					processSubMenuService(ref, service1,key,clazz);
				}
			} catch (InvalidSyntaxException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	protected void processSubMenuService(ServiceReference<T> next, T parent,final String key,Class<T> clazz) throws InvalidSyntaxException{
		prepreParent(parent);
		Collection<ServiceReference<T>> serviceReferences = context
				.getServiceReferences(clazz, null);
		final String menuTree = String.valueOf(next.getProperty(key));
		
		List<ServiceReference<T>> list=ServiceUtil.filter(serviceReferences, new cn.calm.swing.osgi.api.Filter<ServiceReference<T>>(){

			@Override
			public boolean filter(ServiceReference<T> e) {
				String menu = String.valueOf(e.getProperty(key));
				return menu.matches("^"+menuTree+"/\\w*");
			}
		});
		sortService(list);
		for(ServiceReference<T> ref:list){
			T service = context.getService(ref);
			processParent(service, parent);
			processSubMenuService(ref, service,key,clazz);
		}
	}
	
	
	public DefaultServiceTracker(BundleContext context, String clazz,
			ServiceTrackerCustomizer<S, T> customizer) {
		super(context, clazz, customizer);
	}

	public void modifiedService(ServiceReference<S> reference, T service) {
		processShape(MODIFIED, reference, service);
		super.modifiedService(reference, service);
	}

	public void removedService(
			org.osgi.framework.ServiceReference<S> reference, T service) {
		processShape(REMOVED, reference, service);
		super.modifiedService(reference, service);
	}

	protected abstract void prepreParent(T parent);
	
	protected abstract void processParent(T service, T parent) ;
	
	protected abstract void processShape(int action, ServiceReference<S> reference, T service);
	
	protected abstract void sortService(List<ServiceReference<T>> list);
	
}
